package com.xplay.xpocker.config;

import com.xplay.xpocker.message.action.MessageHandlerContext;
import com.xplay.xpocker.message.action.MessageAnnotation;
import com.xplay.xpocker.message.connecter.ConnectAnnotation;
import com.xplay.xpocker.message.connecter.ConnectHandlerContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wanjie
 * @date 2021/3/17 21:53
 */
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {

    private final String BASE_PACKAGE = "com.xplay.xpocker.message";

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        ConcurrentHashMap<String, ConcurrentHashMap<String, Class>> messageHandlerMap = new ConcurrentHashMap<>();
        ConcurrentHashMap<String, Class> connectHandlerMap = new ConcurrentHashMap<>();
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        final String RESOURCE_PATTERN = "/**/*.class";
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE)
                    + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                if (resource.isReadable()) {
                    MetadataReader reader = readerFactory.getMetadataReader(resource);
                    //扫描到的class
                    String className = reader.getClassMetadata().getClassName();
                    Class<?> clazz = Class.forName(className);
                    MessageAnnotation messageAction = clazz.getAnnotation(MessageAnnotation.class);
                    if (null != messageAction) {
                        String[] types = messageAction.type();
                        for (String type : types) {
                            ConcurrentHashMap<String, Class> actionMap = messageHandlerMap.get(type);
                            if (actionMap == null) {
                                actionMap = new ConcurrentHashMap<String, Class>();
                                messageHandlerMap.put(type, actionMap);
                            }
                            actionMap.put(messageAction.action(), clazz);
                        }
                    }
                    ConnectAnnotation connectAnnotation = clazz.getAnnotation(ConnectAnnotation.class);
                    if (null != connectAnnotation) {
                        connectHandlerMap.put(connectAnnotation.action(), clazz);
                    }
                }
            }
            //注册 消息策略处理对象
            MessageHandlerContext messageHandlerContext = new MessageHandlerContext(messageHandlerMap);
            configurableListableBeanFactory.registerSingleton(MessageHandlerContext.class.getName(), messageHandlerContext);
            // 注册连接策略处理对象
            ConnectHandlerContext connectHandlerContext = new ConnectHandlerContext(connectHandlerMap);
            configurableListableBeanFactory.registerSingleton(ConnectHandlerContext.class.getName(), connectHandlerContext);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
